// ============================== 导入依赖 ============================== //

import VueRouter from 'vue-router'

let InFrame
let NotFound

// ============================== 导出路由工具 ============================== //

export default {
  /**
   * 子路由
   *
   * @param {Function} import1 导入一
   * @param {Function} import2 导入二
   * @param {Function} importn 导入几
   *
   * @return {Object} 子路由配置
   */
  routeChildren(...importList) {
    return myGetConfig(this, importList, /^\.\/([A-Z]\w+)\.js$/)
  },

  /**
   * 路由初始化
   *
   * @param {Object} Common 公共路由
   * @param {Function/Object} import1 导入一 (也可直接为一个 Object 类型的路由对象)
   * @param {Function/Object} import2 导入二 (同上)
   * @param {Function/Object} importn 导入几
   */
  routeInit(Common, ...args) {
    const ROUTES = args.filter((item) => this.isJSON(item))
    const importList = args.filter((item) => this.isFunction(item))
    this.ROUTE.INIT = myGetConfig(this, importList, /^\.\/([A-Z]\w+)\/index\.js$/)
    this.ROUTE.ROUTES = myGetRoutes(this, Common, ROUTES)
    this.ROUTE.MENU_TREE = myGetMenuTree(this)
  },

  /**
   * 路由生成
   */
  routeNew() {
    this.ROUTE.router = myGetRouter(this)
  },

  /**
   * 路由拦截
   */
  routeBeforeEach() {
    myBeforeEach(this)
  },

  /**
   * 路由自定义处理
   */
  routeDiy(to, from, next) {
    //
  },
}

// ============================== 内部方法 ============================== //

const myGetPath = (path) => path
  .replace(/^([A-Z]+)([A-Z])/, (x, $1, $2) => `${$1.toLowerCase()}${$2}`) // 开头的连续大写
  .replace(/([A-Z])([A-Z]+)$/, (x, $1, $2) => `${$1}${$2.toLowerCase()}`) // 结尾的连续大写
  .replace(/([A-Z])([A-Z]+)([A-Z])/, (x, $1, $2, $3) => `${$1}${$2.toLowerCase()}${$3}`) // 中间的连续大写
  .replace(/[A-Z]/g, (x) => `/${x.toLowerCase()}`) // Xyz 转为 /xyz
  .replace(/^\//, '') // 去掉开头的 /

const myGetConfig = (CORE, importList, regexp) => {
  const CONFIG = {}
  importList.forEach((imports) => {
    if (!CORE.isFunction(imports)) return
    imports.keys().forEach((path) => {
      const matched = regexp.exec(path)
      if (matched) {
        const { default: config, ...other } = imports(path)
        CORE.merge(CONFIG, { [matched[1]]: { ...other, default: config || {} } })
      }
    })
  })
  return CONFIG
}

const myGetRoutes = (CORE, Common, ROUTES) => {
  // 一级配置
  const majorList = Object.keys(CORE.ROUTE.INIT).map((majorName) => ({ ...CORE.ROUTE.INIT[majorName], majorName }))
  majorList.forEach(({ majorName, default: majorConfig }) => {
    const majorRoute = {
      name: majorName,
      path: `/${majorName.toLowerCase()}`,
      component: Common.component,
      children: [],
    }
    ROUTES.push(majorRoute)

    // 二级配置
    const minorList = Object.keys(majorConfig).map((minorName) => ({ ...majorConfig[minorName], minorName }))
    minorList.forEach(({ minorName, minor, default: { menu, ...minorConfig } }) => {
      if (!minor) {
        const ref = minorConfig.meta ? minorConfig.meta.menu : '' // 详情页配置的指向菜单
        if (ref) minorConfig.meta.menu = (majorConfig[ref] || {}).name || `${majorName}${ref}`

        majorRoute.children.push({
          name: minorConfig.name || `${majorName}${minorName}`,
          path: minorConfig.path || minorName.toLowerCase(),
          ...minorConfig,
        })
        return
      }

      // 三级配置
      const leafList = Object.keys(minorConfig).map((leafName) => ({ ...minorConfig[leafName], leafName }))
      leafList.forEach(({ leafName, menu, ...leafConfig }) => {
        const ref = leafConfig.meta ? leafConfig.meta.menu : '' // 详情页配置的指向菜单
        if (ref) leafConfig.meta.menu = (minorConfig[ref] || {}).name || `${majorName}${minorName}_${ref}`

        const name = leafConfig.name || `${majorName}${minorName}_${leafName}`
        const regexp = new RegExp(`^${minorName}`)
        const path = myGetPath(`${minorName}${leafName.replace(regexp, '')}`)
        majorRoute.children.push({ name, path, ...leafConfig })
      })
    })
  })

  // 公共路由
  const children = Common.children || []
  children.forEach(({ name, component }) => {
    if (name === 'InFrame') InFrame = component // 记录内嵌组件
    else if (name === 'NotFound') NotFound = component // 记录 404 组件
    else CORE.ROUTE.NAME_PASS.push(name) // 记录名称免检
  })

  return [...ROUTES, { ...Common, children: children.filter((item) => item.name !== 'InFrame') }]
}

const myGetMenuTree = (CORE) => {
  const MENU_TREE = []

  // 一级配置
  const majorList = Object.keys(CORE.ROUTE.INIT).map((majorName) => ({ ...CORE.ROUTE.INIT[majorName], majorName }))
  majorList.sort((a, b) => a.sort - b.sort)
  majorList.forEach(({ majorName, major, default: majorConfig }) => {
    if (!major) {
      Object.keys(majorConfig).forEach((minorName) => CORE.ROUTE.NAME_PASS.push(`${majorName}${minorName}`))
      return
    }

    const majorTree = { children: [], id: majorName, title: major, path: majorName.toLowerCase() }
    MENU_TREE.push(majorTree)

    // 二级配置
    const minorList = Object.keys(majorConfig).map((minorName) => ({ ...majorConfig[minorName], minorName }))
    minorList.sort((a, b) => a.sort - b.sort)
    minorList.forEach(({ minorName, minor, default: { menu, ...minorConfig } }) => {
      if (!minor && !menu) return

      const name = minorConfig.name || `${majorName}${minorName}`
      const minorTree = { children: [], id: name, title: minor, path: minorName.toLowerCase(), ...menu }
      majorTree.children.push(minorTree)

      // 三级配置
      const leafList = Object.keys(minorConfig).map((leafName) => ({ ...minorConfig[leafName], leafName }))
      leafList.sort((a, b) => a.sort - b.sort)
      leafList.forEach(({ leafName, menu, ...leafConfig }) => {
        if (!menu || !menu.title) return

        const name = leafConfig.name || `${majorName}${minorName}_${leafName}`
        const regexp = new RegExp(`^${minorName}`)
        const path = myGetPath(leafName.replace(regexp, ''))
        minorTree.children.push({ children: [], id: name, path, ...menu })
      })
    })
  })

  return MENU_TREE
}

const myGetRouter = (CORE) => {
  const commonChildren = []

  // 检查菜单路由
  for (const name in CORE.MENU.ROUTE) {
    const menu = CORE.MENU.ROUTE[name]
    const majorRoute = CORE.ROUTE.ROUTES.find((route) => name.startsWith(route.name))

    if (majorRoute) {
      const minorRoute = majorRoute.children.find((route) => name === route.name)
      if (!minorRoute) {
        const path = name.split('_').pop().replace(majorRoute.name, '')
          .replace(/([a-z])([A-Z])/g, (_, $1, $2) => `${$1}/${$2}`).toLowerCase()
        if (menu.openType === 2) majorRoute.children.push({ component: InFrame, name, path, meta: { iframe: menu.landingPage } })
        else if (menu.openType === 3) majorRoute.children.push({ component: NotFound, name, path, meta: { reload: menu.landingPage } })
        else if (menu.openType === 4) majorRoute.children.push({ component: NotFound, name, path, meta: { open: menu.landingPage } })
        else majorRoute.children.push({ component: NotFound, name, path })
      }
    } else {
      const path = name.replace(/([a-z_])([A-Z])/g, (_, $1, $2) => `${$1}/${$2}`).toLowerCase()
      if (menu.openType === 2) commonChildren.push({ component: InFrame, name, path, meta: { iframe: menu.landingPage } })
      else if (menu.openType === 3) commonChildren.push({ component: NotFound, name, path, meta: { reload: menu.landingPage } })
      else if (menu.openType === 4) commonChildren.push({ component: NotFound, name, path, meta: { open: menu.landingPage } })
      else commonChildren.push({ component: NotFound, name, path })
    }
  }

  const commonRoute = CORE.ROUTE.ROUTES.find((route) => route.name === 'Common')
  commonRoute.children = [...commonChildren, ...commonRoute.children]

  // 生成路由实例
  const router = new VueRouter({
    mode: 'history',
    base: process.env.VUE_APP_RUN,
    routes: CORE.ROUTE.ROUTES,
  })

  // 异常处理
  const VueRouterPush = VueRouter.prototype.push
  VueRouter.prototype.push = function push(to) {
    return VueRouterPush.call(this, to).catch((err) => err)
  }
  const VueRouterReplace = VueRouter.prototype.replace
  VueRouter.prototype.replace = function replace(to) {
    return VueRouterReplace.call(this, to).catch((err) => err)
  }

  return router
}

const myBeforeEach = (CORE) => {
  const base = process.env.VUE_APP_RUN
  const login = base.replace(/admin$/, 'login')

  CORE.ROUTE.router.beforeEach((to, from, next) => {
    const redirect = to.name === 'Home' ? '' : `?redirect=${base}${to.fullPath}`
    // 未登录则跳转登录页面
    if (!sessionStorage.TOKEN) location = `${location.origin}${login}${redirect}`
    // 检查是否存在名称免检
    else if (CORE.ROUTE.NAME_PASS.includes(to.name)) next()
    // 检查是否存在名称转换
    else if (CORE.ROUTE.NAME_TRANS[to.name]) next({ name: CORE.ROUTE.NAME_TRANS[to.name] })
    // 检查是否为自定义处理
    else if (to.meta.diy) CORE.routeDiy(to, from, next)
    // 检查是否为地址栏跳转
    else if (to.meta.reload) location = to.meta.reload
    // 检查是否为新窗口打开
    else if (to.meta.open) window.open(to.meta.open)
    // 检查是否在菜单权限内
    else if (CORE.MENU.ROUTE[to.meta.menu || to.name]) next()
    // 跳转首页
    else next({ name: 'Home' })
  })
}
